#pragma once

#include "../comm/log.hpp"
#include "../comm/util.hpp"
#include "./mysqlConn.hpp"

#include <iostream>
#include <string>
#include <cassert>
#include <unordered_map>
#include <fstream>

#include <mysql/mysql.h>

namespace ns_model
{
    using namespace ns_log;
    using namespace ns_util;

    struct Question
    {
        std::string number; // 题目编号，唯一
        std::string title;  // 题目的标题
        std::string star;   // 难度: 简单 中等 困难
        int cpu_limit;      // 题目的时间要求(S)
        int mem_limit;      // 题目的空间要去(KB)
        std::string desc;   // 题目的描述
        std::string header; // 题目预设给用户在线编辑器的代码
        std::string tail;   // 题目的测试用例，需要和header拼接，形成完整代码
    };

    const std::string host = "127.0.0.1";
    const std::string user = "oj_client";
    const std::string passwd = "lkm20031030";
    const std::string db = "oj";
    const unsigned int port = 3306; 
    class Model
    {
    private:
        std::unordered_map<std::string, Question> _questions;
    public:
        Model(){
            //构造对象时，加载题库至内存中
            assert(LoadQuestionList());
        }
        ~Model(){}
    private:
    //加载MySQL题库所有题目到内存中
        bool LoadQuestionList(){
            
            //创建数据库操作对象
            MysqlConn conn(host,user,passwd,db);

            //执行sql,获取结果
            MYSQL_RES *res = conn.executeSql("select * from questions");
            if(res == nullptr)
            {
                LOG(FATAL) << "执行sql失败, 加载题库失败" << '\n';
                return false;
            }

            //获取结果的行数
            my_ulonglong row = mysql_num_rows(res);
            //获取结果的列数
            my_ulonglong col = mysql_num_fields(res);

            for(uint64_t i = 0; i < row; i++ ){
                //获取一行结果
                MYSQL_ROW fetch = mysql_fetch_row(res);
                for(uint64_t j = 0; j < col;j++){
                    //构建question
                    Question q;
                    q.number = fetch[0];
                    q.title = fetch[1];
                    q.star = fetch[2];
                    q.desc = fetch[3];
                    q.header = fetch[4];
                    q.tail = fetch[5];
                    q.cpu_limit= std::stoi(fetch[6]);
                    q.mem_limit= std::stoi(fetch[7]);

                    //插入进哈希表中
                    _questions.insert(std::make_pair(fetch[0],q));
                }
            }

            LOG(INFO) << "加载题库完成,加载题目数量:" << _questions.size() << '\n';

            mysql_free_result(res);
            return true;
        }

    public:
        bool GetAllQuestions(std::vector<Question> *out){
            if(_questions.size() == 0)
            {
                LOG(ERROR) << "用户获取题库失败" << "\n";
                return false;
            }

            for(auto &q : _questions)
            {
                out->push_back(q.second);
            }
            return true;
        }
        bool GetOneQuestions(const std::string &number, Question *q){
            auto it = _questions.find(number);
            if(it == _questions.end())
            {
                //题目不存在
                LOG(ERROR) << "编号为 " + number + " 号的题目不存在" << "\n";
                return false;
            }

            *q = it->second;
            return true;
        }
    };
}
